package com.cloud.common.util;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.cloud.common.bean.SessionInfo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

import java.util.Date;

/**
 * JWT令牌工具类
 */
@Slf4j
public class TokenUtils {
    /**
     * 分割符
     */
    private static final String TOKEN_SEPARATOR = ".";
    private static final String VALUE_SEPARATOR = "@";

    private static final String JWT_HEADER = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9";
    private static final String USER = "user";

    /**
     * 构建令牌
     *
     * @param sessionInfo
     * @param validSeconds
     * @return
     */
    public static String build(SessionInfo sessionInfo, long validSeconds) {
        String secret = sessionInfo.getSecret();
        String value = sessionInfo.getAppName() + VALUE_SEPARATOR + sessionInfo.getUserId();
        String token = buildToken(value.toString(), secret, validSeconds);
        String[] arr = token.split("\\" + TOKEN_SEPARATOR);
        token = secret + TOKEN_SEPARATOR + arr[1] + TOKEN_SEPARATOR + arr[2];
        return token;
    }

    /**
     * 解析令牌
     *
     * @param token
     * @return
     */
    public static AppUser parse(String token) {
        if (StringUtils.isEmpty(token)) {
            return null;
        }
        try {
            String[] arr = token.split("\\" + TOKEN_SEPARATOR);
            if (arr.length != 3) {
                return null;
            }
            String secret = getSecret(token);
            token = JWT_HEADER + TOKEN_SEPARATOR + arr[1] + TOKEN_SEPARATOR + arr[2];
            String value = parseToken(token, secret);
            if (value == null) {
                return null;
            }
            String[] values = value.split(VALUE_SEPARATOR);
            if (values.length >= 2) {
                return new AppUser(values[0], values[1]);
            }
        } catch (Exception e) {
            log.warn("parse token failure, token={}", token);
        }
        return null;
    }

    /**
     * 获取密钥
     *
     * @param token
     * @return
     */
    public static String getSecret(String token) {
        return token.split("\\" + TOKEN_SEPARATOR)[0];
    }

    /**
     * 构建JWT令牌
     *
     * @param userId
     * @param secret
     * @param timeoutSeconds
     * @return
     */
    private static String buildToken(String userId, String secret, long timeoutSeconds) {
        Date expiresAt = new Date(System.currentTimeMillis() + timeoutSeconds * 1000L);
        JWTCreator.Builder builder = JWT.create().withExpiresAt(expiresAt).withClaim(USER, userId);
        return builder.sign(Algorithm.HMAC256(secret));
    }

    /**
     * 解析JWT令牌
     *
     * @param token
     * @param secret
     * @return
     */
    private static String parseToken(String token, String secret) {
        try {
            JWTVerifier verifier = JWT.require(Algorithm.HMAC256(secret)).build();
            DecodedJWT jwt = verifier.verify(token);
            return jwt.getClaims().get(USER).asString();
        } catch (Exception e) {
            // 忽略异常
        }
        return null;
    }

    @Data
    @AllArgsConstructor
    public static class AppUser {
        private String appName;
        private String userId;
    }
}
